/* eslint-disable @typescript-eslint/no-explicit-any */
import { defineComponent, PropType, ref } from 'vue';
import { useNamespace } from '@ibiz-template/vue3-util';
import draggable from 'vuedraggable';
import { IRecursiveTreeNode, NodeDropType } from '../recursive-tree-util';
import { useRecursiveNodeContent } from './use-recursive-node-content';
import './recursive-node-content.scss';

// 递归组件
export const RecursiveNodeContent = defineComponent({
  name: 'RecursiveNodeContent',
  components: {
    draggable,
  },
  props: {
    node: {
      type: Object as PropType<IRecursiveTreeNode>,
      required: true,
    },
    activeItem: {
      type: Object as PropType<IRecursiveTreeNode>,
    },
    overItem: {
      type: Object as PropType<IRecursiveTreeNode>,
    },
    allowDrop: {
      type: Function as PropType<
        (
          _draggingNode: IRecursiveTreeNode,
          _dropNode: IRecursiveTreeNode,
          _type: 'inner' | 'prev' | 'next',
        ) => boolean
      >,
    },
    allowDrag: {
      type: Function as PropType<
        (_draggingNode: IRecursiveTreeNode) => boolean
      >,
    },
  },
  emits: {
    nodeDrop: (
      _draggingNode: IRecursiveTreeNode,
      _dropNode: IRecursiveTreeNode,
      _dropType: NodeDropType,
    ) => true,
    dragStart: (_draggingNode: IRecursiveTreeNode) => true,
    dragEnd: (_draggingNode: IRecursiveTreeNode) => true,
  },
  setup(props, { slots, emit }) {
    const ns = useNamespace(`org-recursive-node-content`);
    const contentRef = ref();

    const onDrop = (
      _draggingNode: IRecursiveTreeNode,
      _dropNode: IRecursiveTreeNode,
      _dropType: NodeDropType,
    ): void => {
      emit('nodeDrop', _draggingNode, _dropNode, _dropType);
    };

    const {
      groupOptions,
      draggableOptions,
      isOverContainer,
      itemGroupOptions,
      draggableItemOptions,
      isOverItemKey,
      handleDragoverItem,
      handleAdd,
      handleItemAdd,
    } = useRecursiveNodeContent(props, onDrop);

    const renderItem = (_node: IRecursiveTreeNode, _index: number): any => {
      return (
        <draggable
          class={[
            ns.e('item'),
            ns.is(
              'dragover-item',
              isOverContainer.value && isOverItemKey.value === _node.id,
            ),
            ns.is(
              'selected',
              props.activeItem && props.activeItem.id === _node.id,
            ),
          ]}
          modelValue={[_node]}
          group={itemGroupOptions}
          index={_index}
          disabled={props.allowDrag && !props.allowDrag(_node)}
          ghostClass={ns.m('ghost-class')}
          {...draggableItemOptions}
          onAdd={(evt: MouseEvent) => handleItemAdd(evt, _node)}
          onDragover={(evt: MouseEvent) => handleDragoverItem(evt, _node.id)}
        >
          {{
            item: ({ element }: { element: IRecursiveTreeNode }) => {
              return (
                <div class={ns.em('item', 'content')}>
                  {slots.default?.({ ...element })}
                </div>
              );
            },
          }}
        </draggable>
      );
    };

    return {
      ns,
      groupOptions,
      draggableOptions,
      isOverContainer,
      contentRef,
      renderItem,
      handleAdd,
    };
  },
  render() {
    return (
      <div class={this.ns.b()}>
        <draggable
          ref='contentRef'
          class={[
            this.ns.e('content'),
            this.ns.is(
              'dragover',
              this.overItem && this.overItem.id === this.node.id,
            ),
            this.ns.is('active', !!this.activeItem),
          ]}
          modelValue={this.node.children}
          group={this.groupOptions}
          ghostClass={this.ns.m('ghost-class')}
          {...this.draggableOptions}
          onAdd={this.handleAdd}
        >
          {{
            item: ({
              element,
              index,
            }: {
              element: IRecursiveTreeNode;
              index: number;
            }) => {
              return this.renderItem(element, index);
            },
          }}
        </draggable>
      </div>
    );
  },
});

export default RecursiveNodeContent;
